package net.esj.basic.dao;

import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;


public class DaoProxy implements InitializingBean, ApplicationContextAware{

	private ApplicationContext applicationContext; 
	
	protected static final Class[] NO_CLASSES = new Class[0];
	
	protected static Set<Class> BASIC_INTERFACE ;
	static{
		BASIC_INTERFACE = new HashSet<Class>();
		BASIC_INTERFACE.add(Dao.class);
		BASIC_INTERFACE.add(QueryBuilderDao.class);
		BASIC_INTERFACE.add(QueryMapDao.class);
	}
	
	//private Object persistentClass;//主父类
	
	private List<String> daoSources;
	
	private Set<Object> subBeans;
	
	private static Object proxy;
	
	private static Set<Class> interfaceClasses = new HashSet<Class>();
	
	public void setDaoSources(List<String> daoSources) {
		this.daoSources = daoSources;
	}

	/*public void setPersistentClass(Object persistentClass) {
		this.persistentClass = persistentClass;
	}*/
	
	@Override
	public void setApplicationContext(ApplicationContext ac)
			throws BeansException {
		this.applicationContext = ac;
	}
	
	@Override
	public void afterPropertiesSet() throws Exception {
		subBeans = new LinkedHashSet<Object>();
		Enhancer enhancer = new Enhancer(); 
//		enhancer.setSuperclass(persistentClass.getClass());
//		for(Class claz: persistentClass.getClass().getInterfaces()){
//			interfaceClasses.add(claz);
//		}
		Set<Class> classSet = new HashSet<Class>();
		for(Object o : daoSources){
			Object bean=applicationContext.getBean(o.toString()) ;
			//Class clazz = Class.forName(beanName);
			if(bean!=null){
				for(Class interfaze:bean.getClass().getInterfaces()){
					classSet.add(interfaze);
					interfaceClasses.add(interfaze);
				}
				//Object bean = ((AbstractApplicationContext)applicationContext).getBeanFactory().createBean(clazz,Autowire.BY_TYPE.value(), true);
				subBeans.add(bean);
			}
		}
		enhancer.setInterfaces(classSet.toArray(new Class[classSet.size()]));
		enhancer.setCallback(new BaseDaoMethodInterceptor());
		proxy = enhancer.create();
		//((AbstractApplicationContext)applicationContext).getBeanFactory().autowireBeanProperties(proxy,Autowire.BY_NAME.value(), true);
	}
	
	
	public static <T> T getProxy(Class<T> clazz){
		if(BASIC_INTERFACE.contains(clazz)){
			return (T)proxy;
		}
		if(!interfaceClasses.contains(clazz)){
			throw new IllegalArgumentException("代理类不能实现该接口!");
		}
		return (T)proxy;
	}
	
	private class BaseDaoMethodInterceptor implements MethodInterceptor {

		@Override
		public Object intercept(Object obj, Method method, Object[] args,
				MethodProxy proxy) throws Throwable {
			Object reval = null;
//			if(method.getDeclaringClass() == persistentClass.getClass()){
//				//reval = proxy.invokeSuper(obj, args);
//				reval = method.invoke(persistentClass, args);
//				return reval;
//			}
			for(Object dao:subBeans){
				if(method.getDeclaringClass() == dao.getClass()
						|| (method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(dao.getClass()))){
					reval = method.invoke(dao, args);
					return reval;
				}
			}
			reval = proxy.invokeSuper(obj, args);
			return reval;
		}

	}

}
